#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx11.lib")
#pragma comment(lib, "d3dx10.lib")

#include "Timer.h"
#include "ScreenManager.h"
#include "DX11ShaderManager.h"
#include "Game.h"
//#include "DX11InputManager.h"
#include "DX11ErrorReport.h"
#include "StringUtilities.h"
#include "CameraManager.h"
#include "AntTweakBarManager.h"
#include "LoadState.h"
#include "DX11HelpfulFunctions.h"
#include "LightingManager.h"
#include "DX11TextureManager.h"
#include "EventPoller.h"
#include "SimpleCollisionSystem.h"
#include "DX11TextureManager.h"
#include "TestState.h"

#include <d3d9types.h>
#include <D3DX10math.h>
#include <string>

LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);

ScreenManager::ScreenManager()
{
	m_hInst = NULL;
	m_hWnd = NULL;
	m_driverType = D3D_DRIVER_TYPE_NULL;
	m_featureLevel = D3D_FEATURE_LEVEL_11_0;
	m_pd3dDevice = NULL;
	m_pImmediateContext = NULL;
	m_pSwapChain = NULL;
	m_pRenderTargetView = NULL;
	//m_pVertexBuffer = NULL;

	m_pDepthStencilState = NULL;
	m_height = 0;
	m_width = 0;

}

WPARAM ScreenManager::CreateDX11Window(const HINSTANCE& hInstance, const HINSTANCE& hPrevInstance, 
	const LPWSTR& lpCmdLine, const int& nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

	if(FAILED(InitWindow(hInstance, nCmdShow)))
		return 0;

	if(FAILED(InitDevice()))
	{
		CleanupDevice();
		return 0;
	}

	
	TheGame::Instance()->SetCollisionSystem(new SimpleCollisionSystem);
	TheGame::Instance()->SetGameState(TheLoadState::Instance());

	MSG msg = {0};
	while(WM_QUIT != msg.message)
	{
		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TheEventPoller::Instance()->Update(msg);

			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			// game stuff here
			GameLoop();
		}
	}

	CleanupDevice();

	return msg.wParam;
}

HRESULT ScreenManager::InitWindow(HINSTANCE hInstance, int nCmdShow)
{
    // Register class
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_TUTORIAL1);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = L"WindowName";
    wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_TUTORIAL1);
    if(!RegisterClassEx(&wcex))
        return E_FAIL;

    // Create window
    m_hInst = hInstance;
    RECT rc = {0, 0, m_width, m_height};
    AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
    m_hWnd = CreateWindow(L"WindowName", L"Woakagine",
                           WS_OVERLAPPEDWINDOW,
                           CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance,
                           NULL);
    if(!m_hWnd)
        return E_FAIL;
	


    ShowWindow(m_hWnd, nCmdShow);
	
	//TheDX11InputManager::Instance()->Init(m_hInst, m_hWnd, m_width, m_height);

    return S_OK;
}

//HRESULT CompileShaderFromFile(WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut)
//{
//    HRESULT hr = S_OK;
//
//    DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
//#if defined( DEBUG ) || defined( _DEBUG )
//    // Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
//    // Setting this flag improves the shader debugging experience, but still allows 
//    // the shaders to be optimized and to run exactly the way they will run in 
//    // the release configuration of this program.
//    dwShaderFlags |= D3DCOMPILE_DEBUG;
//#endif
//
//    ID3DBlob* pErrorBlob;
//    hr = D3DX11CompileFromFile( szFileName, NULL, NULL, szEntryPoint, szShaderModel, 
//        dwShaderFlags, 0, NULL, ppBlobOut, &pErrorBlob, NULL );
//    if( FAILED(hr) )
//    {
//        if( pErrorBlob != NULL )
//            OutputDebugStringA( (char*)pErrorBlob->GetBufferPointer() );
//        if( pErrorBlob ) pErrorBlob->Release();
//        return hr;
//    }
//    if( pErrorBlob ) pErrorBlob->Release();
//
//    return S_OK;
//}

HRESULT ScreenManager::InitDevice()
{
    HRESULT hr = S_OK;
	

    RECT rc;
    GetClientRect(m_hWnd, &rc);
    UINT width = rc.right - rc.left;
    UINT height = rc.bottom - rc.top;

    UINT createDeviceFlags = 0;

#ifdef _DEBUG
    createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
    //createDeviceFlags |= D3D11_CREATE_DEVICE_SINGLETHREADED;
#endif

    D3D_DRIVER_TYPE driverTypes[] =
    {
        D3D_DRIVER_TYPE_HARDWARE,
        D3D_DRIVER_TYPE_WARP,
        D3D_DRIVER_TYPE_REFERENCE,
    };
    UINT numDriverTypes = ARRAYSIZE(driverTypes);

    D3D_FEATURE_LEVEL featureLevels[] =
    {
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
    };
	UINT numFeatureLevels = ARRAYSIZE(featureLevels);

	//IDXGIAdapter* adapter;
	//IDXGIOutput* output;
	

    DXGI_SWAP_CHAIN_DESC sd;
    ZeroMemory(&sd, sizeof(sd));
    sd.BufferCount = 1;
    sd.BufferDesc.Width = width;
    sd.BufferDesc.Height = height;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferDesc.RefreshRate.Numerator = 60;
    sd.BufferDesc.RefreshRate.Denominator = 1;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT;
    sd.OutputWindow = m_hWnd;
    sd.SampleDesc.Count = 1;
    sd.SampleDesc.Quality = 0;
    sd.Windowed = TRUE;

	//depthstencil buffer initialisation
	D3D11_TEXTURE2D_DESC dsd;
	ZeroMemory(&dsd, sizeof(dsd));

	dsd.Width				= width;
	dsd.Height				= height;
	dsd.MipLevels			= 1;
	dsd.ArraySize			= 1;
	dsd.Format				= DXGI_FORMAT_D24_UNORM_S8_UINT;
	dsd.SampleDesc.Count	= 1;
	dsd.SampleDesc.Quality	= 0;
	dsd.Usage				= D3D11_USAGE_DEFAULT;
	dsd.BindFlags			= D3D11_BIND_DEPTH_STENCIL;
	dsd.CPUAccessFlags		= 0;
	dsd.MiscFlags			= 0;

	

	//ZeroMemory(&m_depthStencilBuffer, sizeof(m_depthStencilBuffer));
	//ZeroMemory(&m_depthStencilView, sizeof(m_depthStencilView));

	//m_pImmediateContext->OMSetRenderTargets(1, &renderTargetView, depthStencilView);


    for(UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++)
    {
        m_driverType = driverTypes[driverTypeIndex];
        hr = D3D11CreateDeviceAndSwapChain(NULL, m_driverType, NULL, createDeviceFlags, featureLevels, numFeatureLevels,
                                            D3D11_SDK_VERSION, &sd, &m_pSwapChain, &m_pd3dDevice, &m_featureLevel, &m_pImmediateContext);
        if(SUCCEEDED(hr))
            break;
    }
    if( FAILED(hr))
        return hr;

    // Create a render target view
    ID3D11Texture2D* pBackBuffer = NULL;
    hr = m_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
    if(FAILED(hr))
        return hr;

    hr = m_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &m_pRenderTargetView);
    pBackBuffer->Release();
    if(FAILED(hr))
        return hr;

	hr = m_pd3dDevice->CreateTexture2D(&dsd, NULL, &m_pDepthStencilBuffer);
    if(FAILED(hr))
        return hr;

	D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
	ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));
	depthStencilDesc.DepthEnable = true;
	depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
	depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;

	depthStencilDesc.StencilEnable = true;
	depthStencilDesc.StencilReadMask = 0xFF;
	depthStencilDesc.StencilWriteMask = 0xFF;

	depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
	depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

	depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
	depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

	hr = m_pd3dDevice->CreateDepthStencilState(&depthStencilDesc, &m_pDepthStencilState);	
    if(FAILED(hr))
        return hr;
	
	m_pImmediateContext->OMSetDepthStencilState(m_pDepthStencilState, 1);

	D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
    ZeroMemory(&descDSV, sizeof(descDSV));
    descDSV.Format = dsd.Format;
    descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    descDSV.Texture2D.MipSlice = 0;

	hr = m_pd3dDevice->CreateDepthStencilView(m_pDepthStencilBuffer, &descDSV, &m_pDepthStencilView);
    if(FAILED(hr))
        return hr;
	
    m_pImmediateContext->OMSetRenderTargets(1, &m_pRenderTargetView, m_pDepthStencilView);

	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(d3dpp));
	
    // Setup the viewport
    D3D11_VIEWPORT vp;
    vp.Width = (FLOAT)width;
    vp.Height = (FLOAT)height;
    vp.MinDepth = 0.0f;
    vp.MaxDepth = 1.0f;
    vp.TopLeftX = 0;
    vp.TopLeftY = 0;
    m_pImmediateContext->RSSetViewports(1, &vp);

	// init world matrix
	D3DXMatrixIdentity(&m_world);
	
	D3DXVECTOR3 target;
	D3DXVECTOR3 pos;
	D3DXVECTOR3 up;

	// init view matrix
	target = D3DXVECTOR3(3.0f, 4.0f, 2.0f);
	pos = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
	up  = D3DXVECTOR3(0.0f, 1.0f, 0.0f);

	D3DXMatrixLookAtLH(&m_view, &target, &pos, &up);

	// init proj matrix
	D3DXMatrixPerspectiveFovLH(&m_projection, float(D3DX_PI / 4.0), 1.0f, 2.0f, 5.0f);
	
	// init input manager
	//TheDX11InputManager::Instance()->Init(m_hInst, m_hWnd, m_width, m_height);
	D3DXMATRIX lightMat = m_view * m_projection;
	TheLightingManager::Instance()->SetLightViewMatrix(m_view);
	TheLightingManager::Instance()->SetLightProjMatrix(m_projection);
	
	ZeroMemory(&m_rasterizerDesc, sizeof(D3D11_RASTERIZER_DESC));
	m_rasterizerDesc.FillMode = D3D11_FILL_SOLID;
	m_rasterizerDesc.CullMode = D3D11_CULL_BACK;
	m_rasterizerDesc.AntialiasedLineEnable = true;


	// create rasterizer state
	m_pd3dDevice->CreateRasterizerState(&m_rasterizerDesc, &m_pRasterizerState);
	//m_pImmediateContext->RSSetState(m_pRasterizerState);

	TheAntTweakBarManager::Instance()->Initialise(m_pd3dDevice, m_width, m_height);

	D3D11_BLEND_DESC blending;
	ZeroMemory(&blending, sizeof(D3D11_BLEND_DESC));
	D3D11_RENDER_TARGET_BLEND_DESC renderTargetBlending;
	ZeroMemory(&renderTargetBlending, sizeof(renderTargetBlending));

	// alpha from e.g. png
	renderTargetBlending.BlendEnable = true;
	renderTargetBlending.BlendOp = D3D11_BLEND_OP_ADD;
	renderTargetBlending.BlendOpAlpha = D3D11_BLEND_OP_ADD;
	renderTargetBlending.DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
	renderTargetBlending.DestBlendAlpha = D3D11_BLEND_ZERO;
	renderTargetBlending.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
	renderTargetBlending.SrcBlend = D3D11_BLEND_SRC_ALPHA;
	renderTargetBlending.SrcBlendAlpha = D3D11_BLEND_ONE;
	

	ZeroMemory(&blending, sizeof(D3D11_BLEND_DESC));
	D3D11_RENDER_TARGET_BLEND_DESC renderTargetBlendingNB;
	ZeroMemory(&renderTargetBlendingNB, sizeof(D3D11_RENDER_TARGET_BLEND_DESC));
	// no black alpha
	renderTargetBlendingNB.BlendEnable = true;
	renderTargetBlendingNB.SrcBlend = D3D11_BLEND_SRC_ALPHA;
	renderTargetBlendingNB.DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
	renderTargetBlendingNB.BlendOp = D3D11_BLEND_OP_ADD;
	renderTargetBlendingNB.SrcBlendAlpha = D3D11_BLEND_ZERO;
	renderTargetBlendingNB.DestBlendAlpha = D3D11_BLEND_ZERO;
	renderTargetBlendingNB.BlendOpAlpha = D3D11_BLEND_OP_ADD;
	renderTargetBlendingNB.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;

	blending.AlphaToCoverageEnable = false;
	blending.RenderTarget[0] = renderTargetBlending;
	
	D3D11_DEPTH_STENCIL_DESC depthStencil;
	// create front + back face draw state
	ZeroMemory(&depthStencil, sizeof(D3D11_DEPTH_STENCIL_DESC));
	depthStencil.DepthEnable = true;
	depthStencil.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
	depthStencil.DepthFunc = D3D11_COMPARISON_LESS;

	depthStencil.StencilEnable = true;
	depthStencil.StencilReadMask = 0xFF;
	depthStencil.StencilWriteMask = 0xFF;

	depthStencil.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	depthStencil.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
	depthStencil.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	depthStencil.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

	depthStencil.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	depthStencil.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
	depthStencil.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	depthStencil.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;	
	m_pd3dDevice->CreateDepthStencilState(&depthStencil, &m_pNoDepthStencilState);

	D3D11_RASTERIZER_DESC rasteriser;
	ZeroMemory(&rasteriser, sizeof(D3D11_RASTERIZER_DESC));
	rasteriser.FillMode = D3D11_FILL_SOLID;
	rasteriser.CullMode = D3D11_CULL_NONE;
	rasteriser.AntialiasedLineEnable = true;
	m_pd3dDevice->CreateRasterizerState(&rasteriser, &m_pNoCullingRasteriserState);
	
	ZeroMemory(&rasteriser, sizeof(D3D11_RASTERIZER_DESC));
	rasteriser.FillMode = D3D11_FILL_SOLID;
	rasteriser.CullMode = D3D11_CULL_BACK;
	rasteriser.AntialiasedLineEnable = true;
	m_pd3dDevice->CreateRasterizerState(&rasteriser, &m_pCullingRasteriserState);
	


	m_pd3dDevice->CreateBlendState(&blending, &m_pTransparencyBlendState);
	m_pd3dDevice->CreateBlendState(&blending, &m_pTransparencyBlendStateNB);

	TheDX11TextureManager::Instance()->Initialise();

	DisableBlending();

	TheLoadState::Instance()->LoadMeshes();
	TheLoadState::Instance()->LoadShaders();
	
    return hr;
}

void ScreenManager::CleanupDevice()
{
    if(m_pImmediateContext) m_pImmediateContext->ClearState();

	if (!TheDX11ShaderManager::Instance()->ReleaseShaders())
	{
        MessageBox( NULL,
                    L"The FX file cannot be compiled.  Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
	}

    if(m_pRenderTargetView) m_pRenderTargetView->Release();
    if(m_pSwapChain) m_pSwapChain->Release();
    if(m_pImmediateContext) m_pImmediateContext->Release();
    if(m_pd3dDevice) m_pd3dDevice->Release();
	if(m_pDepthStencilView) m_pDepthStencilView->Release();
	if(m_pDepthStencilBuffer) m_pDepthStencilBuffer->Release();
	if(m_pRasterizerState) m_pRasterizerState->Release();
	if (m_pNoDepthStencilState) m_pNoDepthStencilState->Release();
	if (m_pNoCullingRasteriserState) m_pNoCullingRasteriserState->Release();
	if (m_pCullingRasteriserState) m_pCullingRasteriserState->Release();

}

LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    PAINTSTRUCT ps;
    HDC hdc;

	TheAntTweakBarManager::Instance()->CheckInput(hWnd, message, wParam, lParam);


    switch( message )
    {
        case WM_PAINT:
            hdc = BeginPaint( hWnd, &ps );
            EndPaint( hWnd, &ps );
            break;

        case WM_DESTROY:
			TwTerminate();
            PostQuitMessage( 0 );
            break;

        default:
            return DefWindowProc( hWnd, message, wParam, lParam );
    }

    return 0;
}

void ScreenManager::GameLoop()
{
	
	//DX11::ClearColour(0.5f, 0.5f, 0.5f, 1.0f);
	//float ClearColour[] = {0.5f, 0.5f, 0.5f, 1.0f};
	
	//if (!TheDX11InputManager::Instance()->Update())
	//{
	//	DX11ErrorMsg(L"DX11: Input Manager Error - Frame Function", L"DX11InputManager", MB_YESNO);
	//}

	TheGame::Instance()->RunGame();
	
	//ID3D11Texture2D* pSurface;
	//HRESULT hr = m_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&pSurface));

	//ID3D11Texture2D* result = NULL;// = pSurface;
	//D3DXVECTOR2 mousePos = TheTestState::Instance()->GetMousePos();
	//D3D11_BOX box;
	//box.top = mousePos.y;
	//box.left = mousePos.x;
	//box.bottom = box.top + 1;
	//box.right = box.left + 1;
	//box.front = 0;
	//box.back = 1;
	//// create result texture
	//D3D11_TEXTURE2D_DESC testTexDesc;
	//pSurface->GetDesc(&testTexDesc);
	//testTexDesc.Width = 1;
	//testTexDesc.Height = 1;
	//testTexDesc.MipLevels = 1;
	//testTexDesc.ArraySize = 1;
	//testTexDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
	//testTexDesc.SampleDesc.Count = 1;
	//testTexDesc.SampleDesc.Quality = 0;
	//testTexDesc.BindFlags = 0;
	//testTexDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ| D3D11_CPU_ACCESS_WRITE;
	//testTexDesc.MiscFlags = 0;
	//testTexDesc.Usage = D3D11_USAGE_STAGING;
	//
	//hr = m_pd3dDevice->CreateTexture2D(&testTexDesc, NULL, &result);

	//ID3D11Resource* inputResource;

	////if (pSurface->swa

	////m_pImmediateContext->CopyResource(result, pSurface);
	//m_pImmediateContext->CopySubresourceRegion(result, 0, 0, 0, 0, pSurface, 0, &box);

	//D3D11_MAPPED_SUBRESOURCE mapDesc;
	//hr = m_pImmediateContext->Map(result, 0, D3D11_MAP_READ_WRITE, 0, &mapDesc);
	//D3DXVECTOR4 pixCol;
	//BYTE pix;
	//const unsigned char* data;
	//if (mapDesc.pData != NULL)
	//{
	//	data = ((const unsigned char*)mapDesc.pData);
	//	pixCol = *((D3DXVECTOR4*)mapDesc.pData);
	//}

	//if (pixCol.x > 0.0f)
	//{
	//	int lolll = 0;
	//}

	//m_pImmediateContext->Unmap(result, 0);
	
	FlipBuffers();
}

void ScreenManager::FlipBuffers()
{
	m_pSwapChain->Present( 0, 0 );
}

HRESULT ScreenManager::InitBuffers(ID3D11Buffer*& vertBuffer, ID3D11Buffer*& indexBuffer, D3D11_BUFFER_DESC& bd, 
	D3D11_SUBRESOURCE_DATA& initData, const std::vector<VertexData>& vertData, const std::vector<DWORD>& indexData,
	ID3D11Buffer** cb)
{
	HRESULT hr = S_OK;
	
	D3DXVECTOR4 white = D3DXVECTOR4(1, 1, 1, 1);

	ZeroMemory(&bd, sizeof(bd));
    bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(VertexData) * vertData.size();
    bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	ZeroMemory(&initData, sizeof(initData));
	//InitData.pSysMem = &verticesTwo;	
	initData.pSysMem = &vertData[0];	

	if(FAILED(m_pd3dDevice->CreateBuffer(&bd, &initData, &vertBuffer)))
	{
		return hr;
	}

	UINT stride = sizeof(VertexData);
	UINT offset = 0;

	//m_pImmediateContext->IASetVertexBuffers(0, 1, &vertBuffer, &stride, &offset);
	
	ZeroMemory(&bd, sizeof(bd));
	ZeroMemory(&indexBuffer, sizeof(indexBuffer));
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(DWORD) * indexData.size();
	bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	ZeroMemory(&initData, sizeof(initData));
	//initData.pSysMem = &indicesTwo;
	initData.pSysMem = &indexData[0];
	initData.SysMemSlicePitch = 0;
	initData.SysMemPitch = 0;
	
	hr = m_pd3dDevice->CreateBuffer(&bd, &initData, &indexBuffer);

	if (FAILED(hr))
	{
		return hr;
	}

	// sets index buffer
	//m_pImmediateContext->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R16_UINT, 0);

	// sets topology
	m_pImmediateContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	//m_pImmediateContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST);
	
	ZeroMemory(&bd, sizeof(D3D11_BUFFER_DESC));
	bd.Usage = D3D11_USAGE_DEFAULT;
	bd.ByteWidth = sizeof(ConstantBuffer);
	bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	bd.CPUAccessFlags = 0;

	//m_pConstantBuffer = NULL;
	//ZeroMemory(&m_pConstantBuffer, sizeof(m_pConstantBuffer));
	hr = m_pd3dDevice->CreateBuffer(&bd, NULL, cb);

	if (FAILED(hr))
	{
		return hr;
	}

	return hr;
}

void ScreenManager::SetBuffers(ID3D11Buffer*& vertBuffer, ID3D11Buffer*& indexBuffer)
{	
	UINT stride = sizeof(VertexData);
	UINT offset = 0;
	m_pImmediateContext->IASetVertexBuffers(0, 1, &vertBuffer, &stride, &offset);
	m_pImmediateContext->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R32_UINT, 0);
}

void ScreenManager::SetConstantBuffer(ID3D11Buffer* constBuffer)
{
	m_pConstantBuffer = constBuffer;
}

void ScreenManager::SetViewMatrix(const D3DXVECTOR3& pos, const D3DXVECTOR3& target, const D3DXVECTOR3& up)
{
	D3DXMatrixLookAtLH(&m_view, &pos, &target, &up);
	D3DXMatrixPerspectiveFovLH(&m_projection, (float)D3DX_PI / 4.0, (float)m_width/(float)m_height, 1.0f, 1000.0f);
}

void ScreenManager::SetViewMatrix(const D3DXMATRIX& view)
{
	m_view = view;
	D3DXMatrixPerspectiveFovLH(&m_projection, (float)D3DX_PI / 4.0, (float)m_width/(float)m_height, 1.0f, 1000.0f);
}

void ScreenManager::SetBEV(const D3DXMATRIX& view)
{
	m_view = view;
	D3DXMatrixOrthoLH(&m_projection, 500, 500, 0, 9000);
	//D3DXMatrixPerspectiveFovLH(&m_projection, (float)D3DX_PI / 4.0, 1.0f, 1.0f, 1000.0f);
}

void ScreenManager::SetWindowSize(int width, int height)
{
	m_width = width;
	m_height = height;
}

void ScreenManager::SetViewProjMatrix(const D3DXMATRIX& view, const D3DXMATRIX& proj)
{
	m_view = view;
	m_projection = proj;
}

int ScreenManager::GetWindowHeight()
{
	return m_height;
}
	
int ScreenManager::GetWindowWidth()
{
	return m_width;
}

float ScreenManager::GetAspectRatio()
{
	return (float)m_width / (float)m_height;
}

void ScreenManager::EnableBlending()
{
	float blendingAmount[] =	{	1.0f,
									1.0f,
									1.0f,								
								};
	m_pImmediateContext->OMSetBlendState(m_pTransparencyBlendState, blendingAmount, 0xffffffff);
}

void ScreenManager::EnableBlendingNB()
{
	float blendingAmount[] =	{	1.0f,
									1.0f,
									1.0f,								
								};
	m_pImmediateContext->OMSetBlendState(m_pTransparencyBlendStateNB, blendingAmount, 0xffffffff);
}

void ScreenManager::DisableBlending()
{
	m_pImmediateContext->OMSetBlendState(0, 0, 0xffffffff);
}

void ScreenManager::SetFrontBackDrawStencilState()
{
	m_pImmediateContext->RSSetState(m_pNoCullingRasteriserState);
	m_pImmediateContext->OMSetDepthStencilState(m_pNoDepthStencilState, 1);
}

void ScreenManager::SetDefaultStencilState()
{
	m_pImmediateContext->RSSetState(m_pCullingRasteriserState);
	m_pImmediateContext->OMSetDepthStencilState(TheScreenManager::Instance()->GetDepthStateState(), 1);
}

ID3D11Texture2D* ScreenManager::GetDepthStencilBuffer()
{
	return m_pDepthStencilBuffer;
}